package com.mubai.netty.config;

import com.mubai.netty.handler.NettyClientHandler;
import com.mubai.netty.handler.StringProtocolInitalizer;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * netty TCP 和 UDP服务器的配置信息
 * @author baichuanping
 * @create 2018-08-27
 */
@Configuration
public class NettyConfig {
    //读取yml中配置
    @Value("${netty.boss.thread.count}")
    private int bossCount;

    @Value("${netty.worker.thread.count}")
    private int workerCount;

    @Value("${netty.tcp.port}")
    private int tcpPort;

    @Value("${netty.so.keepalive}")
    private boolean keepAlive;

    @Value("${netty.so.backlog}")
    private int backlog;

    @Value("${netty.udp.port}")
    public Integer udpPort;

    @Autowired
    private StringProtocolInitalizer stringProtocolInitalizer;

    @Autowired
    private NettyClientHandler nettyClientHandler;
    //bootstrap 配置
    @Bean(name = "serverBootstrap")
    public ServerBootstrap bootstrap() {
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup(),workerGroup())
                .channel(NioServerSocketChannel.class)
                .childHandler(stringProtocolInitalizer);
        Map<ChannelOption<?>,Object> tcpChannelOptions = tcpChannelOptions();
        Set<ChannelOption<?>> keySet = tcpChannelOptions.keySet();
        for (ChannelOption option :keySet) {
            bootstrap.option(option,tcpChannelOptions.get(option));
        }
        return bootstrap;
    }
    // 配置一个udp服务器
    @Bean(name = "udpServerBootstrap")
    public Bootstrap udpBootstrap() {
        EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group)
                .channel(NioDatagramChannel.class)
                .option(ChannelOption.SO_BROADCAST, true)
                .handler(nettyClientHandler);
        return bootstrap;
    }

    @Bean(name = "bossGroup",destroyMethod = "shutdownGracefully")
    public NioEventLoopGroup bossGroup() {
        return new NioEventLoopGroup(bossCount);
    }

    @Bean(name = "workerGroup", destroyMethod = "shutdownGracefully")
    public NioEventLoopGroup workerGroup() {
        return new NioEventLoopGroup(workerCount);
    }

    @Bean(name = "udpGroup", destroyMethod = "shutdownGracefully")
    public NioEventLoopGroup udpGroup() {
        return new NioEventLoopGroup(workerCount);
    }


    /**
     * tcp服务器端口
     * @return
     */
    @Bean(name = "tcpSocketAddress")
    public InetSocketAddress tcpPort() {
        return new InetSocketAddress(tcpPort);
    }

    /**
     * udp服务器端口
     * @return
     */
    @Bean(name = "udpSocketAddress")
    public InetSocketAddress udpPort() {
        return new InetSocketAddress(udpPort);
    }

    @Bean(name = "tcpChannelOptions")
    public Map<ChannelOption<?>,Object> tcpChannelOptions() {
        Map<ChannelOption<?>, Object> options = new HashMap<>();
        options.put(ChannelOption.SO_KEEPALIVE,keepAlive);
        options.put(ChannelOption.SO_BACKLOG,backlog);
        return options;
    }

    @Bean
    public StringEncoder stringEncoder() {
        return new StringEncoder();
    }


    @Bean
    public StringDecoder stringDecoder() {
        return new StringDecoder();
    }

    /**
     * Necessary to make the value annotations work
     * @return
     */
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}
